package com.gitee.wsl.prism4j.languages

import com.gitee.wsl.prism4j.GrammarUtils
import com.gitee.wsl.prism4j.GrammarUtils.require
import com.gitee.wsl.prism4j.Prism4j
import com.gitee.wsl.prism4j.Prism4j.Companion.pattern
import com.gitee.wsl.prism4j.Prism4j.Companion.token
import com.gitee.wsl.prism4j.annotations.Extend
import com.gitee.wsl.prism4j.Prism4j.Pattern

@Suppress("unused")
@Extend("java")
object Prism_scala {
    fun create(prism4j: Prism4j): Prism4j.Grammar {
        val scala = GrammarUtils.extend(
            require(prism4j, "java"),
            "scala",
            object : GrammarUtils.TokenFilter {
                override fun test(token: Prism4j.Token): Boolean {
                    val name = token.name()
                    return "class-name" != name && "function" != name
                }
            },
            token(
                "keyword", pattern(
                    Pattern.compile("<-|=>|\\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\\b")
                )
            ),
            token(
                "string",
                pattern(Pattern.compile("\"\"\"[\\s\\S]*?\"\"\""), false, true),
                pattern(Pattern.compile("(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1"), false, true)
            ),
            token(
                "number", pattern(
                    Pattern.compile(
                        "\\b0x[\\da-f]*\\.?[\\da-f]+|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:e\\d+)?[dfl]?",
                        Pattern.CASE_INSENSITIVE
                    )
                )
            )
        )

        scala.tokens().add(
            token("symbol", pattern(Pattern.compile("'[^\\d\\s\\\\]\\w*")))
        )

        GrammarUtils.insertBeforeToken(
            scala, "number",
            token(
                "builtin",
                pattern(Pattern.compile("\\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\\b"))
            )
        )

        return scala
    }
}
